/*++

Copyright (c) 2007  Microsoft Corporation 

Filename: 

    RackAnalyzer.cs

Abstract: 

    Interface for Rack Analyzer
     
--*/

#region Namespace
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Xml;
using UtilityManager;
using System.Threading;
using Visio = Microsoft.Office.Interop.Visio;
using System.Windows.Forms;
using System.Data;
using DataManager;
using System.Data.SqlClient;
using System.Globalization;
using System.Management;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing;
using Microsoft.EnterpriseManagement;
using Microsoft.EnterpriseManagement.Configuration;
using Microsoft.EnterpriseManagement.Monitoring;
using System.Diagnostics;
using Microsoft.EnterpriseManagement.Monitoring.Security;
using System.Security;
using Microsoft.EnterpriseManagement.Common;
using System.ServiceProcess;



#endregion

namespace VisioManager
{
    class RackAnalyzer
    {
        #region Member variables

        // Rack Document
        private Document _rackDocument;

        //private ArrayList[] MachineAr;

        //private DataSet dsTotalDetailsData;
        //private DataSet dsFreeDetailsData;

        // Visio document
        private Visio.Document visioDocument;

        // Status window and status form
        private StatusDlg statusDlg;

        // Flag set while analyze process is on
        private bool pageAnalyze;

        #endregion Member variables

        #region Properties

        public Visio.Document VisioDocument
        {
            set { visioDocument = value; }
        }

        internal Visio.DataRecordset RackDR
        {
            get
            {
                return _rackDocument.RackDR;
            }
            set { _rackDocument.RackDR = value; }
        }

        internal Visio.DataRecordset ServerDR
        {
            get
            {
                return _rackDocument.ServerDR;
            }
            set { _rackDocument.ServerDR = value; }
        }

        internal Document RackDocument
        {
            set { _rackDocument = value; }
        }

        internal bool PageAnalyze
        {
            set { pageAnalyze = value; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Analyze all the colo or rack on active page
        /// </summary>
        internal void Analyze()
        {
            Global.ThreadStop threadStatus = Global.ThreadStop.Abort;
            bool shapeFound = false;

            try
            {
                // Get active page reference
                Visio.Page currPage = visioDocument.Application.ActivePage;

                // Check if page type property exist
                if (!Convert.ToBoolean(currPage.PageSheet.get_CellExistsU(
                    Global.PageTemplateUserProp,
                    (short)Visio.VisExistsFlags.visExistsAnywhere)))
                {
                    // Page do not have PageType property
                    MessageBox.Show(Global.GetResourceString("MessageImportData"),
                        Global.GetResourceString("Exception_MsgBox_Caption"),
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Information,
                        MessageBoxDefaultButton.Button1);
                    threadStatus = Global.ThreadStop.Complete;
                    return;
                }

                // Fetch the page type value
                string pageType = currPage.PageSheet.get_CellsU(Global.PageTemplateUserProp).FormulaU.Trim('\"'); ;

                switch (pageType)
                {
                    case Global.PageTemplateColo:
                        // Active page is a colo page. Analyze all the colo
                        AnalyzeColo();
                        break;

                    case Global.PageTemplateRack:
                        // Avtive page is a rack page. Analyze only the active rack
                        foreach (Visio.Shape currShape in currPage.Shapes)
                        {
                            // Check for rack shape
                            if (currShape.Master != null &&
                                String.Compare(currShape.Master.NameU, Global.RackMasterName) == 0)
                            {
                                // Make sure rack is not a virtual rack
                                if (String.Compare(Document.GetShapeProperty(currShape, Global.UserVirtualRack), "FALSE") == 0)
                                {
                                    // Valid rack shape found
                                    shapeFound = true;

                                    // Analyze the rack shape
                                    AnalyzeRack(currShape);
                                }
                            }
                        }
                        if (!shapeFound)
                        {
                            // No racks found on the current page
                            MessageBox.Show(Global.GetResourceString("MessageNoRackFound"),
                                Global.GetResourceString("Exception_MsgBox_Caption"),
                                MessageBoxButtons.OK, MessageBoxIcon.Information,
                                MessageBoxDefaultButton.Button1);
                        }
                        break;
                }

                threadStatus = Global.ThreadStop.Complete;
            }
            catch (System.Runtime.InteropServices.COMException ex)
            {
                if (ex.Message.Contains("Cancel"))
                {
                    threadStatus = Global.ThreadStop.Cancel;
                    //throw new System.Runtime.InteropServices.COMException(ex.Message);
                    return;
                }
                else
                {
                    // To catch exceptions from current functions
                    RackException.HandleExceptions(Global.GetResourceString("Exception_MsgBox_Caption"),
                                 Global.GetResourceString("Exception_UsrMsg"), ex);
                }
            }
            catch (System.Threading.ThreadAbortException)
            {
                // Ignore thread abort exception
            }
            catch (RackException ex)
            {
                // To catch and display exceptions from sub functions
                if (ex.Message.Contains(Global.GetResourceString("InvalidSCOMServerOrDBName")))
                {
                    MessageBox.Show(Global.GetResourceString("InvalidSCOMServerOrDBName"),
                    Global.GetResourceString("MessageBoxCaption"),
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Information,
                    MessageBoxDefaultButton.Button1);
                }
                else if (ex.Message.Contains(Global.GetResourceString("InvalidSCOMReportingServerOrDBName")))
                {
                    MessageBox.Show(Global.GetResourceString("InvalidSCOMReportingServerOrDBName"),
                    Global.GetResourceString("MessageBoxCaption"),
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Information,
                    MessageBoxDefaultButton.Button1);
                }
                else
                {
                    RackException.HandleExceptions(Global.GetResourceString("Exception_MsgBox_Caption"),
                                Global.GetResourceString("Exception_UsrMsg"), ex.InnerException);
                }
            }
            catch (Exception ex)
            {
                // To catch exceptions from current functions
                RackException.HandleExceptions(Global.GetResourceString("Exception_MsgBox_Caption"),
                             Global.GetResourceString("Exception_UsrMsg"), ex);
            }
            finally
            {
                try
                {
                    _rackDocument.StopAnalyze(threadStatus);
                }
                catch (System.Threading.ThreadAbortException)
                {
                    // Ignore thread abort exception
                }
                catch (RackException ex)
                {
                    if (ex.Message.Contains(Global.GetResourceString("InvalidSCOMServerOrDBName")))
                    {
                        MessageBox.Show(Global.GetResourceString("InvalidSCOMServerOrDBName"),
                        Global.GetResourceString("MessageBoxCaption"),
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Information,
                        MessageBoxDefaultButton.Button1);
                    }
                    else if (ex.Message.Contains(Global.GetResourceString("InvalidSCOMReportingServerOrDBName")))
                    {
                        MessageBox.Show(Global.GetResourceString("InvalidSCOMReportingServerOrDBName"),
                        Global.GetResourceString("MessageBoxCaption"),
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Information,
                        MessageBoxDefaultButton.Button1);
                    }
                    else
                    {
                        // To catch and display exceptions from sub functions
                        RackException.HandleExceptions(Global.GetResourceString("Exception_MsgBox_Caption"),
                                    Global.GetResourceString("Exception_UsrMsg"), ex.InnerException);
                    }
                }
                catch (Exception ex)
                {
                    // To catch exceptions from current functions
                    RackException.HandleExceptions(Global.GetResourceString("Exception_MsgBox_Caption"),
                                 Global.GetResourceString("Exception_UsrMsg"), ex);
                }
            }
            return;
        }

        /// <summary>
        /// Analyze all the colo in the current document
        /// </summary>
        private void AnalyzeColo()
        {
            bool rackFound = false;

            try
            {
                // Active page is a colo page. Analyze the selected rack
                if (Global.VisioApp.ActiveWindow == null)
                    return;

                Visio.Selection racks = Global.VisioApp.ActiveWindow.Selection;

                if (racks.Count == 0)
                {
                    // No rack selected. Analyze all the colo
                    foreach (Visio.Page currPage in visioDocument.Pages)
                    {
                        // Check if page type property exist
                        if (!Convert.ToBoolean(currPage.PageSheet.get_CellExistsU(
                            Global.PageTemplateUserProp,
                            (short)Visio.VisExistsFlags.visExistsAnywhere)))
                        {
                            // Page do not have PageType property. Skip page
                            continue;
                        }
                        string pageType = currPage.PageSheet.get_CellsU(Global.PageTemplateUserProp).FormulaU.Trim('\"'); ;

                        // Check for colo pages
                        if (String.Compare(pageType, Global.PageTemplateColo) == 0)
                        {
                            // Reset shape found flag for new page
                            rackFound = false;

                            foreach (Visio.Shape currShape in currPage.Shapes)
                            {
                                // Check for colorack shape
                                if (currShape.Master != null &&
                                    String.Compare(currShape.Master.NameU, Global.ColoRackMasterName) == 0)
                                {
                                    // Valid rack shape found
                                    rackFound = true;

                                    // Analyze the rack shape
                                    AnalyzeRack(currShape);
                                }
                            }

                            if (!rackFound)
                            {
                                // No racks found on the current page
                                MessageBox.Show(string.Format(CultureInfo.CurrentCulture,
                                    Global.GetResourceString("MessageNoColoRackFound"), currPage.NameU),
                                    Global.GetResourceString("Exception_MsgBox_Caption"),
                                    MessageBoxButtons.OK, MessageBoxIcon.Information,
                                    MessageBoxDefaultButton.Button1);
                            }
                        }
                    }
                    return;
                }
                // Analyze all the selected racks
                foreach (Visio.Shape currShape in racks)
                {
                    // Check for colorack shape
                    if (currShape.Master != null &&
                        String.Compare(currShape.Master.NameU, Global.ColoRackMasterName) == 0)
                    {
                        // Valid rack shape found
                        rackFound = true;

                        // Analyze the rack shape
                        AnalyzeRack(currShape);
                    }
                }
                if (!rackFound)
                {
                    // No racks found on the current page
                    MessageBox.Show(Global.GetResourceString("MessageNoAnalyzeShape"),
                        Global.GetResourceString("Exception_MsgBox_Caption"),
                        MessageBoxButtons.OK, MessageBoxIcon.Information,
                        MessageBoxDefaultButton.Button1);
                }
            }
            catch (System.Runtime.InteropServices.COMException ex)
            {
                if (ex.Message.Contains("Cancel"))
                {
                    throw new System.Runtime.InteropServices.COMException(ex.Message);
                    //return;
                }
                else
                {
                    // Exception from current function
                    throw new RackException("Analyze Colo", ex);
                }
            }
            catch (System.Threading.ThreadAbortException)
            {
                // Ignore thread abort exception
            }
            catch (RackException ex)
            {
                if (ex.Message.Contains(Global.GetResourceString("InvalidSCOMServerOrDBName")))
                {
                    throw new RackException(Global.GetResourceString("InvalidSCOMServerOrDBName"), ex.InnerException);
                }
                else if (ex.Message.Contains(Global.GetResourceString("InvalidSCOMReportingServerOrDBName")))
                {
                    throw new RackException(Global.GetResourceString("InvalidSCOMReportingServerOrDBName"), ex.InnerException);
                }
                else
                {
                    // Exception from sub function. Pass on to entry point
                    throw new RackException("Analyze Colo", ex.InnerException);
                }
            }
            catch (Exception ex)
            {
                // Exception from current function
                throw new RackException("Analyze Colo", ex);
            }
        }

        /// <summary>
        /// Analyze the selected rack
        /// </summary>
        /// <param name="shape">Rack shape</param>
        public void AnalyzeRack(object shape)
        {
            Visio.Shape visioShape = (Visio.Shape)shape;
            string coloName = string.Empty;
            string rackName = string.Empty;
            bool rackVirtualizable = false;
            bool rackAnalyzeError = false;
            Array serverDataRow;
            Global.ThreadStop threadStatus = Global.ThreadStop.Abort;
            ArrayList serverList = new ArrayList();

            try
            {
                if (statusDlg == null)
                {
                    statusDlg = (StatusDlg)_rackDocument.StatusWindow.FormToShow;
                }

                // Check if server data record set exists
                if (this.ServerDR == null)
                {
                    this.ServerDR = Document.GetDataRecordset(visioDocument.DataRecordsets, Global.ServerDataRecordSetName);

                    if (this.ServerDR == null)
                    {
                        MessageBox.Show(string.Format(CultureInfo.CurrentCulture,
                            Global.GetResourceString("MessageDataRecordSetNotFound"), Global.ServerDataRecordSetName),
                            Global.GetResourceString("MessageBoxCaption"),
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                        return;
                    }
                }

                // Get the colo name for the current rack
                if (Global.ShapePropertyExist(visioShape, Global.PropColoName))
                {
                    coloName = visioShape.get_Cells(Global.PropColoNameValue).get_ResultStr((short)Visio.VisUnitCodes.visNoCast);
                }

                // Get the current rack name
                if (Global.ShapePropertyExist(visioShape, Global.PropRackName))
                {
                    rackName = visioShape.get_Cells(Global.PropRackNameValue).get_ResultStr((short)Visio.VisUnitCodes.visNoCast);
                }

                // Get the list of servers in the current rack
                Array ServerArray = ServerDR.GetDataRowIDs(
                    "[" + ServerDR.DataColumns[Global.ServerFieldColoName].Name + "] Like '" + coloName + "' AND " +
                    "[" + ServerDR.DataColumns[Global.ServerFieldRackName].Name + "] Like '" + rackName + "'");

                Hashtable serverIDTable = new Hashtable();

                // Loop through each server in current rack
                foreach (int serverRowID in ServerArray)
                {
                    serverDataRow = ServerDR.GetRowData(serverRowID);
                    string serverName = serverDataRow.GetValue(0).ToString();

                    #region Get WMI Data
                    if (Global.DTOption == Global.DataOption.Wmi)
                    {

                        if (statusDlg != null)
                        {
                            // notify the start of analyzing server
                            statusDlg.UpdateStatus(string.Empty);
                            statusDlg.UpdateStatus(string.Format(CultureInfo.CurrentCulture,
                                Global.GetResourceString("StatusAnalyzeServerStart"), coloName, rackName, serverName));
                        }

                        Hashtable serverDataTable = null;
                        string errMsg = string.Empty;
                        string analyzeStatus = AnalyzeUsingWMI(serverName, out serverDataTable
                            , ref rackVirtualizable, ref rackAnalyzeError, out errMsg);

                        UpdateDataSetUsingXML(serverRowID.ToString(CultureInfo.CurrentCulture), serverDataTable);

                        UpdateServerVirtualizableProp(visioShape, serverRowID, analyzeStatus);

                        if (analyzeStatus.CompareTo("2") == 0)
                        {
                            if (statusDlg != null)
                            {
                                errMsg = errMsg.Remove(errMsg.IndexOf('.') + 1);

                                // notify the end of analyzing server with error
                                statusDlg.UpdateStatus(string.Format(CultureInfo.CurrentCulture,
                                    Global.GetResourceString("StatusAnalyzeServerError"), coloName, rackName, serverName, errMsg));
                            }
                        }
                        else
                        {
                            if (statusDlg != null)
                            {
                                // notify the end of analyzing server
                                statusDlg.UpdateStatus(string.Format(CultureInfo.CurrentCulture,
                                    Global.GetResourceString("StatusAnalyzeServerComplete"), coloName, rackName, serverName));
                            }
                        }
                    }
                    #endregion

                    else if (Global.DTOption == Global.DataOption.Scom)
                    {
                        // Create a list of server name to be analyzed using SCOM
                        serverList.Add(serverName);

                        // Create a hash table to store serverID & server name to update shape properties after analyze
                        serverIDTable.Add(serverRowID, serverName);
                    }
                }
                if (Global.DTOption == Global.DataOption.Scom)
                {
                    // Analyze rack using SCOM
                    AnalyzeUsingSCOMSDK(serverList, serverIDTable, coloName, rackName,
                        ref rackVirtualizable, ref rackAnalyzeError, visioShape);
                }
                // Set the virtualizable flag to true for the rack shape
                if (rackAnalyzeError)
                {
                    // Analyzed with error
                    SetVirtualizableProp(visioShape, "2");
                }
                else if (rackVirtualizable)
                {
                    // Rack can be virtualized
                    SetVirtualizableProp(visioShape, "1");
                }
                else
                {
                    // Rack can not be virtualized
                    SetVirtualizableProp(visioShape, "3");
                }

                // Update thread status
                threadStatus = Global.ThreadStop.Complete;
            }
            catch (System.Runtime.InteropServices.COMException ex)
            {
                if (ex.Message.Contains("Cancel"))
                {
                    throw new System.Runtime.InteropServices.COMException(ex.Message);
                }
                else
                {
                    // Exception from current function
                    throw new RackException("Analyze Single Rack", ex);
                }
            }
            catch (System.Threading.ThreadAbortException)
            {
                // Ignore thread abort exception
            }
            catch (RackException ex)
            {
                if (!pageAnalyze)
                {
                    if (ex.Message.Contains(Global.GetResourceString("InvalidSCOMServerOrDBName")))
                    {
                        MessageBox.Show(Global.GetResourceString("InvalidSCOMServerOrDBName"),
                        Global.GetResourceString("MessageBoxCaption"),
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Information,
                        MessageBoxDefaultButton.Button1);
                    }
                    else if (ex.Message.Contains(Global.GetResourceString("InvalidSCOMReportingServerOrDBName")))
                    {
                        MessageBox.Show(Global.GetResourceString("InvalidSCOMReportingServerOrDBName"),
                        Global.GetResourceString("MessageBoxCaption"),
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Information,
                        MessageBoxDefaultButton.Button1);
                    }
                    else
                    {
                        // To catch and display exceptions from sub functions
                        RackException.HandleExceptions(Global.GetResourceString("Exception_MsgBox_Caption"),
                                    Global.GetResourceString("Exception_UsrMsg"), ex.InnerException);
                    }
                }
                 
                else
                {
                    // Exception from sub function. Pass on to entry point
                    if (ex.Message.Contains(Global.GetResourceString("InvalidSCOMServerOrDBName")))
                    {
                        throw new RackException(Global.GetResourceString("InvalidSCOMServerOrDBName"), ex.InnerException);
                    }
                    else if (ex.Message.Contains(Global.GetResourceString("InvalidSCOMReportingServerOrDBName")))
                    {
                        throw new RackException(Global.GetResourceString("InvalidSCOMReportingServerOrDBName"), ex.InnerException);
                    }
                    else
                    {
                        throw new RackException("Analyze Single Rack", ex.InnerException);
                    }
                }
            }
            catch (Exception ex)
            {
                if (!pageAnalyze)
                {
                    // To catch exceptions from current functions
                    RackException.HandleExceptions(Global.GetResourceString("Exception_MsgBox_Caption"),
                                 Global.GetResourceString("Exception_UsrMsg"), ex);
                }
                else
                {
                    // Exception from current function
                    throw new RackException("Analyze Single Rack", ex);
                }
            }
            finally
            {
                try
                {
                    // Check if colo is analyzed or just a rack
                    if (!pageAnalyze)
                    {
                        // Stop analyze thread if just a rack
                        _rackDocument.StopAnalyze(threadStatus);
                    }
                }
                catch (System.Threading.ThreadAbortException)
                {
                    // Ignore thread abort exception
                }
                catch (RackException ex)
                {
                    // To catch and display exceptions from sub functions
                    RackException.HandleExceptions(Global.GetResourceString("Exception_MsgBox_Caption"),
                                Global.GetResourceString("Exception_UsrMsg"), ex.InnerException);
                }
                catch (Exception ex)
                {
                    // To catch exceptions from current functions
                    RackException.HandleExceptions(Global.GetResourceString("Exception_MsgBox_Caption"),
                                 Global.GetResourceString("Exception_UsrMsg"), ex);
                }
            }
        }

        /// <summary>
        /// Analyze rack using WMI
        /// </summary>
        /// <param name="serverName">Server in a rack to analyze</param>
        /// <param name="serverDataTable">Fills with the server details after analyze</param>
        /// <param name="rackVirtualizable">Set it to TRUE if server is virtualizable</param>
        /// <param name="rackAnalyzeError">Set it to TRUE if analyze of any server is a rack fails.</param>
        /// <param name="errMsg">Set it to the error message when analyze fails</param>
        /// <returns></returns>
        private static string AnalyzeUsingWMI(string serverName, out Hashtable serverDataTable
            , ref bool rackVirtualizable, ref bool rackAnalyzeError, out string errMsg)
        {
            string analyzeStatus = string.Empty;

            Hashtable serverTable = new Hashtable();
            serverDataTable = new Hashtable();
            ManagementScope RemoteScope = null;
            ArrayList wmiQueries = new ArrayList();
            errMsg = string.Empty;

            DataManager.WmiManager wmiObject = new DataManager.WmiManager();

            try
            {
                // Create queries at run time
                String query = wmiObject.CreateWmiQuery("Win32_NetworkAdapterConfiguration", "IPEnabled = True",
                    Global.WmiServerFieldIPAdress);
                wmiQueries.Add(query);
                query = wmiObject.CreateWmiQuery("Win32_OperatingSystem", string.Empty,
                     Global.WmiServerFieldOperatingSystem, Global.WmiServerFieldCsdVersion, Global.WmiServerFieldAvailMem);
                wmiQueries.Add(query);
                query = wmiObject.CreateWmiQuery("Win32_ComputerSystem", string.Empty,
                    Global.WmiServerFieldTotalMem);
                wmiQueries.Add(query);
                query = wmiObject.CreateWmiQuery("Win32_Processor", string.Empty,
                    Global.WmiServerFieldProcessor);
                wmiQueries.Add(query);
                query = wmiObject.CreateWmiQuery("Win32_PerfFormattedData_PerfOS_Processor", string.Empty,
                Global.WmiServerFieldCpuUsage);
                wmiQueries.Add(query);
                query = wmiObject.CreateWmiQuery("Win32_BaseBoard", string.Empty,
                Global.WmiServerFieldManufacturer);
                wmiQueries.Add(query);

                if (Global.WindowsAuthentication == true)
                {
                    RemoteScope = DataManager.WmiManager.GetWmiScope(serverName, ref errMsg);
                }
                else
                {
                    RemoteScope = DataManager.WmiManager.GetWmiScope(serverName, Global.UserName, Global.Password, ref errMsg);
                }
                if (RemoteScope != null)
                {
                    // Get and Add the data for each server to the server table
                    DataManager.WmiManager.GetHostData(RemoteScope, wmiQueries, ref serverTable);

                    string cpuUsage = GetHashValue(serverTable[Global.WmiServerFieldCpuUsage]);
                    string manufacturer = GetHashValue(serverTable[Global.WmiServerFieldManufacturer]);
                    string virtualServer = "False";

                    if (Convert.ToInt32(cpuUsage, CultureInfo.CurrentCulture) <= Global.CpuUsageThreshold)
                    {
                        if (String.Compare(manufacturer, Global.GetResourceString("MicrosoftCorporation"), true, CultureInfo.CurrentCulture) != 0)
                        {
                            rackVirtualizable = true;
                            // Server virtualizable
                            analyzeStatus = "1";
                        }
                    }
                    else
                    {
                        // Server not virtualizable
                        analyzeStatus = "3";
                    }

                    // Check if server is a virtual server
                    if (String.Compare(manufacturer, Global.GetResourceString("MicrosoftCorporation"), true, CultureInfo.CurrentCulture) == 0)
                    {
                        analyzeStatus = "3";
                        virtualServer = "True";
                    }
                    serverDataTable.Add(Global.ServerFieldIPAdress, GetHashValue(serverTable[Global.WmiServerFieldIPAdress]));
                    serverDataTable.Add(Global.ServerFieldOperatingSystem, 
                        string.Concat(GetHashValue(serverTable[Global.WmiServerFieldOperatingSystem]), " ",
                        string.Compare(GetHashValue(serverTable[Global.WmiServerFieldCsdVersion]),"NA",
                        true,CultureInfo.InvariantCulture)==0? "":GetHashValue(serverTable[Global.WmiServerFieldCsdVersion])));
                    serverDataTable.Add(Global.ServerFieldCpuUsage, string.Concat(cpuUsage, "%"));
                    serverDataTable.Add(Global.ServerFieldTotalMem, Convert.ToInt64(GetHashValue(serverTable[Global.WmiServerFieldTotalMem]), CultureInfo.CurrentCulture) / 1024);
                    serverDataTable.Add(Global.ServerFieldAvailMem, GetHashValue(serverTable[Global.WmiServerFieldAvailMem]));
                    serverDataTable.Add(Global.ServerFieldProcessor, GetHashValue(serverTable[Global.WmiServerFieldProcessor]));
                    serverDataTable.Add(Global.ServerFieldIsVirtual, virtualServer);

                }
                else
                {
                    rackAnalyzeError = true;
                    serverDataTable.Add(Global.ServerFieldIPAdress, Global.NA);
                    serverDataTable.Add(Global.ServerFieldOperatingSystem, Global.NA);
                    serverDataTable.Add(Global.ServerFieldCpuUsage, Global.NA);
                    serverDataTable.Add(Global.ServerFieldTotalMem, Global.NA);
                    serverDataTable.Add(Global.ServerFieldAvailMem, Global.NA);
                    serverDataTable.Add(Global.ServerFieldProcessor, Global.NA);
                    serverDataTable.Add(Global.ServerFieldIsVirtual, Global.NA);

                    // Server analyzed with error
                    analyzeStatus = "2";

                }
                return analyzeStatus;
            }
            catch (System.Threading.ThreadAbortException)
            {
                return "0";
                // Ignore thread abort exception
            }
            catch (RackException ex)
            {
                // Exception from sub function. Pass on to entry point
                throw new RackException("Analyze Using WMI", ex.InnerException);
            }
            catch (Exception ex)
            {
                // Exception from current function
                throw new RackException("Analyze Using WMI", ex);
            }
        }

        /// <summary>
        /// Analyze rack using SCOM SDK
        /// </summary>
        /// <param name="serverList">List of servers in a rack to analyze</param>
        /// <param name="serverIDTable">Data row ID of the servers</param>
        /// <param name="coloName">Colo Name</param>
        /// <param name="rackName">Rack Name</param>
        /// <param name="rackVirtualizable">Set it to TRUE if server is virtualizable</param>
        /// <param name="rackAnalyzeError">Set it to TRUE if analyze of any server is a rack fails.</param>
        /// <param name="rackShape">Rack shape</param>
        private void AnalyzeUsingSCOMSDK(ArrayList serverList, Hashtable serverIDTable,
           string coloName, string rackName, ref bool rackVirtualizable,
           ref bool rackAnalyzeError, Visio.Shape rackShape)
        {
           
            string analyzeStatus = string.Empty;

            DataTable serverDetailTable = new DataTable();
            serverDetailTable.Locale = CultureInfo.CurrentCulture;
            serverDetailTable.Columns.Add("ServerName", Type.GetType("System.String"));
            serverDetailTable.Columns.Add("IPAddress", Type.GetType("System.String"));
            serverDetailTable.Columns.Add("OperatingSystem", Type.GetType("System.String"));
            serverDetailTable.Columns.Add("TotalPhysicalMemory", Type.GetType("System.String"));
            serverDetailTable.Columns.Add("Processor", Type.GetType("System.String"));
            serverDetailTable.Columns.Add("CPUUsage", Type.GetType("System.String"));
            serverDetailTable.Columns.Add("AvailableMemory", Type.GetType("System.String"));
            serverDetailTable.Columns.Add("IsVirtualMachine", Type.GetType("System.String"));
            serverDetailTable.Columns.Add("ServicePack", Type.GetType("System.String"));
            
            DataRow drMachineDetails = null;
            

            // Define the server that you want to connect to.
            string SCOMServerName = Global.ServerName;

            string[] subString = new string[3];
            ManagementGroup mg = null;

            ReadOnlyCollection<MonitoringObject> windowsComputerObjects1 = null;

            try
            {
                // Connect to the SCOM SDK service. 
                if (Global.UserCredentials)
                {
                    SecureString password = new SecureString();
                    for (int i = 0; i < Global.Password.Length; i++)
                    {
                        password.AppendChar(Convert.ToChar(Global.Password.Substring(i, 1),CultureInfo.CurrentCulture));
                    }
                    ManagementGroupConnectionSettings mgSettings =
                            new ManagementGroupConnectionSettings(SCOMServerName);
                    mgSettings.UserName = Global.UserName;
                    mgSettings.Password = password;
                    mg = ManagementGroup.Connect(mgSettings);
                }
                else
                    mg = ManagementGroup.Connect(SCOMServerName);

                //mg = ManagementGroup.Connect(SCOMServerName);

                //MonitoringClass windowsComputerClass1;

                ReadOnlyCollection<MonitoringClassProperty> properties1;

                if (mg.IsConnected)
                {
                    foreach (string serverName in serverList)
                    {
                        drMachineDetails = serverDetailTable.NewRow();

                        //Find the computer by using MonitoringObjectGenericCriteria.
                        MonitoringObjectGenericCriteria windowsComputerCriteria = new MonitoringObjectGenericCriteria("DisplayName LIKE '%" + serverName + "%' AND FullName LIKE '%Computer%'");

                        windowsComputerObjects1 = mg.GetMonitoringObjects(windowsComputerCriteria);

                        foreach (MonitoringObject windowsComputerObject1 in windowsComputerObjects1)
                        {
                            string scomServerName = windowsComputerObject1.Name;

                            char[] splitter = { '.' };
                            subString = scomServerName.Split(splitter);
                            string ipAddress = string.Empty;
                            string virtualMachine = string.Empty;

                            drMachineDetails["ServerName"] = serverName;
                            if (string.Compare(subString[0], serverName, true,CultureInfo.CurrentCulture) == 0)
                            {
                                if (windowsComputerObject1.HealthState != HealthState.Uninitialized)
                                {
                                    properties1 = windowsComputerObject1.GetMonitoringProperties();

                                    int counter = 0;

                                    foreach (MonitoringClassProperty property in properties1)
                                    {
                                        //To get the IP Address of the machine
                                        if (String.Compare(property.DisplayName, Global.GetResourceString("IPAddress"), true,CultureInfo.CurrentCulture) == 0)
                                        {
                                            ipAddress = windowsComputerObject1.GetMonitoringPropertyValue(property).ToString();
                                            if (ipAddress.Contains(","))
                                            {
                                                drMachineDetails["IPAddress"] = ipAddress.Substring(0, ipAddress.IndexOf(','));
                                            }
                                            else
                                            {
                                                drMachineDetails["IPAddress"] = ipAddress;
                                            }
                                            counter++;
                                        }
                                        //To get the Virtual machine property of the machine
                                        else if (String.Compare(property.DisplayName, Global.GetResourceString("VirtualMachine"), true,CultureInfo.CurrentCulture) == 0)
                                        {
                                            virtualMachine = windowsComputerObject1.GetMonitoringPropertyValue(property).ToString();
                                            drMachineDetails["IsVirtualMachine"] = virtualMachine;
                                            counter++;
                                        }

                                        if (counter == 2)
                                            break;
                                    }

                                }


                            }
                        }

                        //Find the operating  system details by using MonitoringObjectGenericCriteria.
                        MonitoringObjectGenericCriteria operatinSystemCriteria = new MonitoringObjectGenericCriteria("Path LIKE '" + serverName + "%'  AND FullName LIKE '%OperatingSystem%'");

                        ReadOnlyCollection<MonitoringObject> windowsComputerObjects_OperatingSystem = mg.GetMonitoringObjects(operatinSystemCriteria);

                        string OSName = string.Empty;

                        foreach (MonitoringObject windowsComputerObject1 in windowsComputerObjects_OperatingSystem)
                        {
                            string scomServerNamePath = windowsComputerObject1.Path;

                            char[] splitter = { '.' };
                            subString = scomServerNamePath.Split(splitter);
                            double average = 0.0;
                            double averageAvailMB = 0.0;

                            string cpuAverage = string.Empty;
                            string availMemoryAverage = string.Empty;
                            if (string.Compare(serverName, subString[0], true,CultureInfo.CurrentCulture) == 0)
                            {
                                properties1 = windowsComputerObject1.GetMonitoringProperties();

                                //Get free disk space counter and CPU utilization data
                                MonitoringPerformanceDataCriteria perfCriteria = new MonitoringPerformanceDataCriteria("CounterName = '" + Global.GetResourceString("AvailableMBytes") + "' OR CounterName='" + Global.GetResourceString("ProcessorTime") + "'");

                                //Get all performance counter data
                                ReadOnlyCollection<MonitoringPerformanceData> performanceData =
                                    windowsComputerObject1.GetMonitoringPerformanceData(perfCriteria);

                                //if (windowsComputerObject1.HealthState != HealthState.Uninitialized)
                                //{
                                    //Get the Operating System Name of the machine
                                    OSName = windowsComputerObject1.DisplayName;
                                    drMachineDetails["OperatingSystem"] = OSName;


                                //}
                                foreach (MonitoringClassProperty property in properties1)
                                {
                                    int counter = 0;
                                    //To get the total physical memory
                                    if (String.Compare(property.DisplayName, Global.GetResourceString("PhysicalMemory"), true,CultureInfo.CurrentCulture) == 0)
                                    {
                                        drMachineDetails["TotalPhysicalMemory"] = windowsComputerObject1.GetMonitoringPropertyValue(property).ToString();
                                        counter++;
                                    }
                                    else if (String.Compare(property.DisplayName, Global.GetResourceString("CSDVersion"), true, CultureInfo.CurrentCulture) == 0)
                                    {
                                        drMachineDetails["ServicePack"] = windowsComputerObject1.GetMonitoringPropertyValue(property).ToString();
                                        counter++;
                                    }
                                    if (counter == 2)
                                        break;
                                }
                                foreach (MonitoringPerformanceData nextData in performanceData)
                                {
                                    //MonitoringPerformanceDataValue lastValue = null;
                                    int cpuUsage = 0;
                                    int memUsage = 0;
                                    if (String.Compare(nextData.CounterName, Global.GetResourceString("ProcessorTime"), true,CultureInfo.CurrentCulture) == 0)
                                    {
                                        DateTime start = DateTime.Today - new TimeSpan(60, 0, 0, 0);

                                        ReadOnlyCollection<MonitoringPerformanceDataValue> values = nextData.GetValues(start, DateTime.Now);

                                        if (values.Count > 0)
                                        {
                                            foreach (MonitoringPerformanceDataValue value in values)
                                            {
                                                if (value.SampleValue != null)
                                                {
                                                    average += value.SampleValue.Value;
                                                }
                                            }
                                            if (average != 0.0)
                                            {
                                                average /= values.Count;
                                                cpuAverage = String.Format(CultureInfo.CurrentCulture, "{0:0.00}", average);
                                                cpuUsage = Convert.ToInt32(Convert.ToDecimal(cpuAverage, CultureInfo.CurrentCulture), CultureInfo.CurrentCulture);
                                            }
                                        }
                                        else
                                        {
                                            cpuUsage = -1;
                                        }
                                        if (cpuUsage != -1)
                                        {
                                            drMachineDetails["CPUUsage"] = cpuUsage;
                                        }
                                    }
                                    else if (String.Compare(nextData.CounterName, Global.GetResourceString("AvailableMBytes"), true,CultureInfo.CurrentCulture) == 0)
                                    {
                                        DateTime start = DateTime.Today - new TimeSpan(60, 0, 0, 0);

                                        ReadOnlyCollection<MonitoringPerformanceDataValue> values = nextData.GetValues(start, DateTime.Now);

                                        if (values.Count > 0)
                                        {
                                            foreach (MonitoringPerformanceDataValue value in values)
                                            {
                                                if (value.SampleValue != null)
                                                {
                                                    averageAvailMB += value.SampleValue.Value;
                                                }
                                            }
                                            if (averageAvailMB != 0.0)
                                            {
                                                averageAvailMB /= values.Count;
                                                availMemoryAverage = String.Format(CultureInfo.CurrentCulture, "{0:0.00}", averageAvailMB);
                                                memUsage = Convert.ToInt32(Convert.ToDecimal(availMemoryAverage, CultureInfo.CurrentCulture));
                                            }
                                        }
                                        else
                                        {
                                            memUsage = -1;
                                        }
                                        if (memUsage != -1)
                                            drMachineDetails["AvailableMemory"] = memUsage;
                                    }
                                }

                            }

                        }


                        //Find Processor details by using MonitoringObjectGenericCriteria.
                        ReadOnlyCollection<MonitoringObject> windowsComputerObjects_LocalHardware;

                        MonitoringObjectGenericCriteria monitorCriteria = new MonitoringObjectGenericCriteria("FullName LIKE '%" + Global.GetResourceString("Processor") + "%' AND (Path LIKE '" + serverName + "%')");

                        windowsComputerObjects_LocalHardware = mg.GetMonitoringObjects(monitorCriteria);

                        string processorData = string.Empty;


                        foreach (MonitoringObject nextWindowsComputerObject_LocalHardware in windowsComputerObjects_LocalHardware)
                        {
                            if (nextWindowsComputerObject_LocalHardware.FullName.Contains(Global.GetResourceString("Processor")))
                            {

                                //Get all monitoring properties
                                ReadOnlyCollection<MonitoringClassProperty> properties_LocalHardware =
                                    nextWindowsComputerObject_LocalHardware.GetMonitoringProperties();

                                if (nextWindowsComputerObject_LocalHardware.FullName.ToLower(CultureInfo.CurrentCulture).Contains(serverName.ToLower(CultureInfo.CurrentCulture)))
                                {
                                    foreach (MonitoringClassProperty nextProperty in properties_LocalHardware)
                                    {
                                        //To get the Processor name
                                        if (string.Compare(nextProperty.DisplayName, Global.GetResourceString("DeviceName"), true,CultureInfo.CurrentCulture) == 0)
                                        {
                                            processorData = string.Format(CultureInfo.CurrentCulture,"{0}", nextWindowsComputerObject_LocalHardware.GetMonitoringPropertyValue(nextProperty));
                                            break;
                                        }
                                    }
                                }

                                if (!string.IsNullOrEmpty(processorData))
                                {
                                    drMachineDetails["Processor"] = processorData;
                                }
                            }
                        }

                        serverDetailTable.Rows.Add(drMachineDetails);
                    }
                }


                // Loop through list of servers to be analyzed and udpated the server properties
                foreach (int serverID in serverIDTable.Keys)
                {
                    Hashtable serverDataTable = new Hashtable();
                    string serverName = serverIDTable[serverID].ToString();
                    DataRow[] sdRows = null;
                    //DataRow[] sfRows = null;

                    if (statusDlg != null)
                    {
                        // notify the start of analyzing server
                        statusDlg.UpdateStatus(string.Empty);
                        statusDlg.UpdateStatus(string.Format(CultureInfo.CurrentCulture,
                            Global.GetResourceString("StatusAnalyzeServerStart"), coloName, rackName, serverName));
                    }

                    if (serverDetailTable != null && serverDetailTable.Columns.Contains("ServerName"))
                    {
                        // Select row for current server
                        sdRows = serverDetailTable.Select("ServerName = '" + serverName + "'");
                    }

                    if (sdRows == null || sdRows.Length == 0)
                    {
                        // No data found for current server

                        rackAnalyzeError = true;

                        // add NA row
                        serverDataTable.Add(Global.ServerFieldIPAdress, Global.NA);
                        serverDataTable.Add(Global.ServerFieldOperatingSystem, Global.NA);
                        serverDataTable.Add(Global.ServerFieldCpuUsage, Global.NA);
                        serverDataTable.Add(Global.ServerFieldTotalMem, Global.NA);
                        serverDataTable.Add(Global.ServerFieldAvailMem, Global.NA);
                        serverDataTable.Add(Global.ServerFieldProcessor, Global.NA);
                        serverDataTable.Add(Global.ServerFieldIsVirtual, Global.NA);

                        // Update server virtualizable property
                        analyzeStatus = "2";
                    }
                    else
                    {
                        foreach (DataRow sdRow in sdRows)
                        {
                            double cpuUsage = 0.0;
                            string virtualServer = null;

                            // Store the Virtual Machine Property
                            if (serverDetailTable.Columns.Contains("IsVirtualMachine")
                                && sdRow["IsVirtualMachine"] != DBNull.Value)
                            {
                                virtualServer = sdRow["IsVirtualMachine"].ToString();
                            }
                            else
                            {
                                virtualServer = "NA";
                            }
                            

                            //if (serverPerfTable.Columns.Contains("CPUUsage") && sfRows[0]["CPUUsage"] != DBNull.Value)
                            if (serverDetailTable.Columns.Contains("CPUUsage") 
                                && sdRows[0]["CPUUsage"] != DBNull.Value)
                            {
                                cpuUsage = Convert.ToDouble(sdRows[0]["CPUUsage"], CultureInfo.InvariantCulture);
                                serverDataTable.Add(Global.ServerFieldCpuUsage, string.Concat(cpuUsage.ToString(CultureInfo.CurrentCulture), "%"));

                                // compare CPU usage with threshold value
                                if (cpuUsage <= Global.CpuUsageThreshold &&
                                    String.Compare(virtualServer, "false", true, CultureInfo.CurrentCulture) == 0)
                                {
                                    // Server virtualizable
                                    rackVirtualizable = true;
                                    analyzeStatus = "1";
                                }
                                else
                                {
                                    // Server not virtualizable
                                    analyzeStatus = "3";
                                }
                            }
                            else
                            {
                                // cpu usage not available
                                serverDataTable.Add(Global.ServerFieldCpuUsage, Global.NA);
                                analyzeStatus = "2";
                                rackAnalyzeError = true;
                            }
                            //if (serverPerfTable.Columns.Contains("AvailableMemory") && sfRows[0]["AvailableMemory"] != DBNull.Value)
                            if (serverDetailTable.Columns.Contains("AvailableMemory") && sdRows[0]["AvailableMemory"] != DBNull.Value)
                            {
                                serverDataTable.Add(Global.ServerFieldAvailMem, Convert.ToInt32(sdRows[0]["AvailableMemory"], CultureInfo.CurrentCulture).ToString(CultureInfo.CurrentCulture));
                            }
                            else
                            {
                                // Memory usage not available
                                serverDataTable.Add(Global.ServerFieldAvailMem, Global.NA);
                            }
                            //}

                            // Check if column exists & assign the value
                            serverDataTable.Add(Global.ServerFieldIPAdress, serverDetailTable.Columns.Contains("IPAddress") ? GetDBValue(sdRow["IPAddress"].ToString()) : Global.NA);
                            serverDataTable.Add(Global.ServerFieldOperatingSystem, GetDBValue
                                (string.Concat(serverDetailTable.Columns.Contains("OperatingSystem") ? sdRow["OperatingSystem"] : Global.NA,
                                " ", serverDetailTable.Columns.Contains("ServicePack") ? sdRow["ServicePack"] : "")));
                            serverDataTable.Add(Global.ServerFieldTotalMem, serverDetailTable.Columns.Contains("TotalPhysicalMemory") ? GetDBValue(sdRow["TotalPhysicalMemory"].ToString()) : Global.NA);
                            serverDataTable.Add(Global.ServerFieldProcessor, serverDetailTable.Columns.Contains("Processor") ? GetDBValue(sdRow["Processor"].ToString()) : Global.NA);
                            serverDataTable.Add(Global.ServerFieldIsVirtual, virtualServer);

                            break;
                        }
                    }

                    // Update server virtualiable property
                    UpdateServerVirtualizableProp(rackShape, serverID, analyzeStatus);

                    // Update server record dataset
                    UpdateDataSetUsingXML(serverID.ToString(CultureInfo.CurrentCulture), serverDataTable);

                    // Update status window based on the analyze status
                    if (analyzeStatus.CompareTo("2") == 0)
                    {
                        if (statusDlg != null)
                        {
                            // notify the end of analyzing server with error
                            statusDlg.UpdateStatus(string.Format(CultureInfo.CurrentCulture, Global.GetResourceString("StatusAnalyzeServerError"),
                                coloName, rackName, serverName, Global.GetResourceString("StatusAnalyzeServerSCOM")));
                        }
                    }
                    else
                    {
                        if (statusDlg != null)
                        {
                            // notify the end of analyzing server
                            statusDlg.UpdateStatus(string.Format(CultureInfo.CurrentCulture,
                                Global.GetResourceString("StatusAnalyzeServerComplete"),
                                coloName, rackName, serverName));
                        }
                    }
                }
            }
            catch (Microsoft.EnterpriseManagement.Common.ServerDisconnectedException)
            {
                 MessageBox.Show(string.Format(CultureInfo.CurrentCulture,
                            String.Format(CultureInfo.CurrentCulture, Global.GetResourceString("UnauthorizedAccess")
                                 , System.Environment.UserDomainName + "\\" + System.Environment.UserName)
                            , Global.RackDataRecordSetName),
                            Global.GetResourceString("MessageBoxCaption"),
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                return;
            }
            catch (Microsoft.EnterpriseManagement.Common.ServiceNotRunningException ex)
            {
                //errorProvider1.SetError(txtBoxSCOMName, ex.Message);
                //return "OpsMgrConnection";
                MessageBox.Show(ex.Message,
                            Global.GetResourceString("MessageBoxCaption"),
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                return;
            }
            catch (Microsoft.EnterpriseManagement.Common.UnauthorizedAccessMonitoringException ex)
            {
                //errorProvider1.SetError(txtBoxSCOMName, ex.Message);
                //return "OpsMgrConnection";
                MessageBox.Show(ex.Message,
                            Global.GetResourceString("MessageBoxCaption"),
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                return;
            }
            catch (System.Runtime.InteropServices.COMException ex)
            {
                if (ex.Message.Contains("Cancel"))
                {
                    throw new System.Runtime.InteropServices.COMException(ex.Message);
                }
                else
                {
                    // Exception from current function
                    throw new RackException("Analyze Using SCOM", ex);
                }
            }
            catch (System.Threading.ThreadAbortException)
            {
                // Ignore thread abort exception
            }
            catch (RackException ex)
            {
                // Exception from sub function. Pass on to entry point
                throw new RackException("Analyze Using SCOM", ex.InnerException);
            }
            catch (Exception ex)
            {

                if (ex.Message.Contains(Global.GetResourceString("Unknown_Host")))
                {
                    MessageBox.Show(string.Format(CultureInfo.CurrentCulture,
                        Global.GetResourceString("Unknown_Host_Message"),
                        ex.Message),
                            Global.GetResourceString("MessageBoxCaption"),
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                    return;
                }
                else
                {
                    throw new RackException("Analyze Using SCOM", ex);
                }
            }
        }
        

        /// <summary>
        /// Check if the value from the data row is null.
        /// </summary>
        /// <param name="dataValue">Data value</param>
        /// <returns>Returns NA if value is null</returns>
        /// 
        private static string GetDBValue(string dataValue)
        {
            if (String.IsNullOrEmpty(dataValue))
            {
                // Null value. Return NA
                return Global.NA;
            }
            return dataValue;
        }

        /// <summary>
        /// Update virtualizable property of the server shape
        /// </summary>
        /// <param name="visioShape">Server shape</param>
        /// <param name="rowID">Record dataset row id</param>
        /// <param name="propValue">Value to be updated</param>
        private void UpdateServerVirtualizableProp(Visio.Shape visioShape, int rowID, string propValue)
        {
            try
            {
                // Check for rack shape
                if (visioShape.Master != null &&
                    String.Compare(visioShape.Master.NameU, Global.RackMasterName) == 0)
                {
                    Array serverShapeID = null;

                    // Get the shape IDs linked to record dataset rowID
                    visioShape.ContainingPage.GetShapesLinkedToDataRow(ServerDR.ID, rowID, out serverShapeID);

                    if (serverShapeID != null)
                    {
                        foreach (int shapeID in serverShapeID)
                        {
                            // Update server virtualizable property of each shape
                            Visio.Shape serverShape = visioShape.ContainingPage.Shapes.get_ItemFromID(shapeID);
                            Document.UpdateShapeProperty(serverShape,
                                (short)Visio.VisSectionIndices.visSectionUser,
                                Global.PropServerVirtualizable, propValue);
                        }
                    }
                }
            }
            catch (System.Threading.ThreadAbortException)
            {
                // Ignore thread abort exception
            }
            catch (RackException ex)
            {
                // Exception from sub function. Pass on to entry point
                throw new RackException("Update ServerVirtualizable Prop", ex.InnerException);
            }
            catch (Exception ex)
            {
                // Exception from current function
                throw new RackException("Update ServerVirtualizable Prop", ex);
            }
        }

        /// <summary>
        /// Set Vistualizable property of the colo-level rack shape
        /// </summary>
        /// <param name="visioShape">Rack Shape</param>
        /// <param name="propValue">Value to be updated</param>
        private void SetVirtualizableProp(Visio.Shape visioShape, string propValue)
        {
            try
            {
                if (this.RackDR == null)
                {
                    this.RackDR = Document.GetDataRecordset(visioDocument.DataRecordsets, Global.RackDataRecordSetName);

                    if (this.RackDR == null)
                    {
                        MessageBox.Show(string.Format(CultureInfo.CurrentCulture,
                            Global.GetResourceString("MessageDataRecordSetNotFound"), Global.RackDataRecordSetName),
                            Global.GetResourceString("MessageBoxCaption"),
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
                        return;
                    }
                }

                // Check for colorack shape
                if (visioShape.Master != null &&
                    String.Compare(visioShape.Master.NameU, Global.ColoRackMasterName) == 0)
                {
                    Document.UpdateShapeProperty(visioShape,
                                (short)Visio.VisSectionIndices.visSectionUser,
                                Global.RackVirtualizable, propValue);
                }
                // Check for rack shape
                if (visioShape.Master != null &&
                    String.Compare(visioShape.Master.NameU, Global.RackMasterName) == 0)
                {
                    Visio.Shape colorackshape = Document.GetColoRackFromDetailRack(visioShape, visioDocument, RackDR);
                    Document.UpdateShapeProperty(colorackshape,
                        (short)Visio.VisSectionIndices.visSectionUser,
                        Global.RackVirtualizable, propValue);
                }
            }
            catch (System.Threading.ThreadAbortException)
            {
                // Ignore thread abort exception
            }
            catch (RackException ex)
            {
                // Exception from sub function. Pass on to entry point
                throw new RackException("Set Virtualizable Prop", ex.InnerException);
            }
            catch (Exception ex)
            {
                // Exception from current function
                throw new RackException("Set Virtualizable Prop", ex);
            }
        }

        /// <summary>
        /// Convert hash value into string
        /// </summary>
        /// <param name="p">Hash value</param>
        /// <returns>Coverted string value</returns>
        private static string GetHashValue(object p)
        {
            if (p == null)
            {
                // Data not available
                return Global.NA;
            }
            Type type = p.GetType();
            string dataStr = string.Empty;

            try
            {
                if (type == typeof(string[]))
                {
                    dataStr = ((string[])(p))[0].ToString();
                }
                else
                {
                    dataStr = p.ToString();
                }

                int len = dataStr.IndexOf(';');
                if (len < 0)
                {
                    len = dataStr.Length;
                }

                return dataStr.Substring(0, len).TrimStart(' ');
            }
            catch (System.Threading.ThreadAbortException)
            {
                // Ignore thread abort exception
                return Global.NA;
            }
            catch (RackException ex)
            {
                // Exception from sub function. Pass on to entry point
                throw new RackException("Get hash value", ex.InnerException);
            }
            catch (Exception ex)
            {
                // Exception from current function
                throw new RackException("Get hash value", ex);
            }
        }
       
        /// <summary>
        /// Update the server record dataset using XML.
        /// </summary>
        /// <param name="serverRowID">Row ID of the server whose data needs to be updated.</param>
        /// <param name="dataTable">Data to be updated.</param>
        private void UpdateDataSetUsingXML(string serverRowID, Hashtable dataTable)
        {
            try
            {
                XmlDocument XmlDoc = new XmlDocument();

                // Load data record set XML string into XML document
                XmlDoc.LoadXml(ServerDR.DataAsXML);

                // Create the names space manager
                XmlNamespaceManager xmlManager = new XmlNamespaceManager(XmlDoc.NameTable);

                // Fetch the root node
                XmlNode rootNode = XmlDoc.DocumentElement;

                // Add 'rs' namespace to XML manager
                string rsNamespacePrefix = "rs";
                string rsNamespaceURI = rootNode.GetNamespaceOfPrefix(rsNamespacePrefix);
                xmlManager.AddNamespace(rsNamespacePrefix, rsNamespaceURI);

                // Add 'z' namespace to XML manager
                string zNamespacePrefix = "z";
                string zNamespaceURI = rootNode.GetNamespaceOfPrefix(zNamespacePrefix);
                xmlManager.AddNamespace(zNamespacePrefix, zNamespaceURI);

                // Add 's' namespace to XML manager
                string sNamespacePrefix = "s";
                string sNamespaceURI = rootNode.GetNamespaceOfPrefix(sNamespacePrefix);
                xmlManager.AddNamespace(sNamespacePrefix, sNamespaceURI);

                foreach (string dataCol in dataTable.Keys)
                {
                    // Find the XML column name of the data column to be updated
                    string schemaXPath = string.Format(CultureInfo.CurrentCulture,
                        "//s:Schema/s:ElementType/s:AttributeType[@rs:name={0}]", "'" + dataCol + "'");
                    string colName = string.Empty;

                    XmlNodeList schemaEntityNode = XmlDoc.SelectNodes(schemaXPath, xmlManager);

                    foreach (XmlNode currNode in schemaEntityNode)
                    {
                        colName = currNode.Attributes["name"].Value;
                    }
                    if (String.IsNullOrEmpty(colName))
                    {
                        colName = dataCol;
                    }
                    // Find the data rows to be updated
                    string dataXPath = string.Format(CultureInfo.CurrentCulture,
                        "//rs:data/z:row[@c0={0}]", "'" + serverRowID + "'");

                    XmlNodeList dataEntityNode = XmlDoc.SelectNodes(dataXPath, xmlManager);

                    foreach (XmlNode currNode in dataEntityNode)
                    {
                        currNode.Attributes[colName].Value = dataTable[dataCol].ToString();
                    }
                }

                // Update the server datarecord set
                ServerDR.RefreshUsingXML(XmlDoc.InnerXml);
            }
            catch (System.Runtime.InteropServices.COMException ex)
            {
                if (ex.Message.Contains("Cancel"))
                {
                    throw new System.Runtime.InteropServices.COMException(ex.Message);
                }
                else
                { 
                    // Exception from current function
                    throw new RackException("Update DataSet Using XML", ex);
                }
            }
            catch (System.Threading.ThreadAbortException)
            {
                // Ignore thread abort exception
            }
            catch (RackException ex)
            {
                // Exception from sub function. Pass on to entry point
                throw new RackException("Update DataSet Using XML", ex.InnerException);
            }
            catch (Exception ex)
            {
                // Exception from current function
                throw new RackException("Update DataSet Using XML", ex);
            }
        }
        #endregion
    }
}
